package org.ws.httphelper.support.pipeline.handler.request;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ws.httphelper.builder.annotation.IgnoreField;
import org.ws.httphelper.common.PropertyUtil;
import org.ws.httphelper.core.pipeline.HandlerOrder;
import org.ws.httphelper.core.pipeline.RequestHandler;
import org.ws.httphelper.exception.RequestException;
import org.ws.httphelper.model.RequestContext;
import org.ws.httphelper.model.config.RequestConfig;
import org.ws.httphelper.model.field.ParamFieldType;
import org.ws.httphelper.model.field.ParamField;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.Map;

@HandlerOrder(value = 1,level = HandlerOrder.OrderLevel.SYSTEM)
public class BuildParamHandler implements RequestHandler {

    private static Logger log = LoggerFactory.getLogger(BuildParamHandler.class.getName());

    /**
     * GET
     * POST:FORM_DATA,X_WWW_FORM_URLENCODED
     * @param requestContext 请求data
     * @throws RequestException
     */
    @Override
    public boolean handler(RequestContext requestContext) throws RequestException {
        Object in = requestContext.getInput();
        // TODO：default value
        if(in == null){
            return true;
        }
        // 根据定义生产param
        if(in instanceof Map){
            putParamByMap((Map)in,requestContext);
        }
        else {
            putParamByObject(in,requestContext);
        }
        if(log.isDebugEnabled()){
            Map<String, Object> params = requestContext.getParams();
            log.debug(JSON.toJSONString(params, SerializerFeature.PrettyFormat));
        }
        return true;
    }

    private void putParamByMap(Map<String,Object> in,RequestContext requestContext){
        Map<String, Object> params = requestContext.getParams();
        RequestConfig requestConfig = requestContext.getRequestConfig();
        Collection<ParamField> fields = requestConfig.getParamFields().values();
        if(CollectionUtils.isNotEmpty(fields)) {
            for (ParamField field : fields) {
                String fieldName = field.getFieldName();
                Object defaultValue = field.getDefaultValue();
                ParamFieldType fieldType = field.getFieldType();
                Object o = in.get(fieldName);
                putParam(o, defaultValue, fieldName, fieldType, params);
            }
        }
        else {
            for (Map.Entry<String, Object> entry : in.entrySet()) {
                params.put(entry.getKey(),entry.getValue());
            }
        }
    }

    private void putParamByObject(Object in,RequestContext requestContext) throws RequestException{
        Map<String, Object> params = requestContext.getParams();
        RequestConfig requestConfig = requestContext.getRequestConfig();
        Collection<ParamField> fields = requestConfig.getParamFields().values();
        Class inClass = in.getClass();
        if(CollectionUtils.isNotEmpty(fields)) {
            for (ParamField field : fields) {
                String fieldName = field.getFieldName();
                Object defaultValue = field.getDefaultValue();
                ParamFieldType fieldType = field.getFieldType();
                try {
                    Object o = PropertyUtil.getValue(in,fieldName);
                    putParam(o,defaultValue,fieldName,fieldType,params);
                } catch (Exception e) {
                    log.error(e.getMessage(),e);
                    throw new RequestException(e.getMessage(),e);
                }
            }
        }
        else {
            for (Field field : PropertyUtil.getFields(inClass)) {
                if(field.isAnnotationPresent(IgnoreField.class)){
                    continue;
                }
                String fieldName = field.getName();
                try {
                    Object value = PropertyUtil.getValue(in,fieldName);
                    if(value != null) {
                        params.put(fieldName, value);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(),e);
                    throw new RequestException(e.getMessage(),e);
                }
            }
        }
    }

    private void putParam(Object o, Object defaultValue, String fieldName, ParamFieldType fieldType, Map<String, Object> params){
        if(o==null && defaultValue ==null){
            return;
        }
        if(o == null && defaultValue != null){
            o = defaultValue;
        }
        // 文件类型若value为String表示地址
        if(fieldType == ParamFieldType.FILE && o instanceof String){
            params.put(fieldName,new File(String.valueOf(o)));
        }
        else {
            params.put(fieldName,o);
        }
    }

}
